// This source is subject to the Microsoft Public License.
// See http://www.microsoft.com/resources/sharedsource/licensingbasics/sharedsourcelicenses.mspx.
// All other rights reserved.

using System;
using System.Reflection;
using System.Text;
using System.Xml;

using QuoteAdvantage.CrmSdk;

namespace QuoteAdvantage
{
   /// <summary>
   /// Summary description for Product.
   /// </summary>
   public class Product
   {     
      // Standard Microsoft CRM fields
      private Guid      m_guidDefaultUnitOfMeasureId;
      private string    m_strDescription;
      private bool      m_bIsKit;
      private string    m_strName;
      private Guid      m_guidProductId;
      private string    m_strProductNumber;
      private int       nProductTypeCode;
      private string    m_strProductUrl;
      private Decimal   m_nListPrice;  // List Price without a pricing list
      private Decimal   m_nPrice;
      private Decimal   m_nStandardCost;
      private Guid      m_guidOrganizationId;
      private Guid      m_guidDefaultUomScheduleId;
      private string    m_strCustomField1;
      private string    m_strCustomField2;

      // Additional data that is not tracked by the Microsoft CRM database. 
      // These fields are used internally for adding QuoteDetails.
      private string    m_strCategoryId;  
      private Guid      m_guidUnitOfMeasureId; 
      private bool      m_bAllowDiscounting;

      public Product()
      {
         
      }       

      // Not tracked by database. This is used for adding QuoteDetails.
      public bool AllowDiscounting
      {
         get { return m_bAllowDiscounting; }
         set { m_bAllowDiscounting = value; }   
      }

      // Not tracked by database. This is used for adding QuoteDetails.
      public string CategoryId
      {
         get { return m_strCategoryId; }
         set { m_strCategoryId = value; }
      }

      public string CustomField1
      {
         get { return m_strCustomField1;}
         set { m_strCustomField1 = value;}
      }

      public string CustomField2
      {
         get { return m_strCustomField2;}
         set { m_strCustomField2 = value;}
      }
  
      public Guid DefaultUnitOfMeasureId
      {
         get { return m_guidDefaultUnitOfMeasureId;}
         set { m_guidDefaultUnitOfMeasureId = value;}
      }
      
      public Guid OrganizationId
      {
         get { return m_guidOrganizationId;}
         set { m_guidOrganizationId = value;}
      }

      public Guid DefaultUomScheduleId
      {
         get { return m_guidDefaultUomScheduleId;}
         set { m_guidDefaultUomScheduleId = value;}
      }
      
      public string Description
      {
         get { return m_strDescription;}
         set { m_strDescription = value;}
      }

      public string Name
      {
         get { return m_strName;}
         set { m_strName = value;}
      }
    
      public bool IsKit
      {
         get { return m_bIsKit;}
         set { m_bIsKit = value;}
      }
      
      public Decimal Price
      {
         get { return m_nPrice;}
         set { m_nPrice = value;}
      }

      // List price without a pricing list
      public Decimal ListPrice
      {
         get { return m_nListPrice;}
         set { m_nListPrice = value;}
      }
      
      public Decimal StandardCost
      {
         get { return m_nStandardCost;}
         set { m_nStandardCost = value;}
      }

      public Guid ProductId
      {
         get { return m_guidProductId;}
         set { m_guidProductId = value;}
      }
      
      public string ProductNumber
      {
         get { return m_strProductNumber;}
         set { m_strProductNumber = value;}
      }

      //     Flat Fees
      //     Miscellaneous Charges
      //     Sales Inventory
      // 3 = Services
      public int ProductTypeCode
      {
         get { return nProductTypeCode;}
         set { nProductTypeCode = value;}
      }

      public string ProductUrl
      {
         get { return m_strProductUrl; }
         set { m_strProductUrl = value; }
      }

      // Not tracked by database. This is used for adding QuoteDetails.
      public Guid UnitOfMeasureId
      {
         get { return m_guidUnitOfMeasureId; }
         set { m_guidUnitOfMeasureId = value; }
      }

      public Product Clone()
      {
         Product  objNewProduct = new Product();

         objNewProduct.CategoryId = m_strCategoryId;  
         objNewProduct.DefaultUnitOfMeasureId = m_guidDefaultUnitOfMeasureId;
         objNewProduct.Description = m_strDescription;
         objNewProduct.IsKit = m_bIsKit;
         objNewProduct.Name = m_strName;
         objNewProduct.ProductId = m_guidProductId;
         objNewProduct.ProductNumber = m_strProductNumber;
         objNewProduct.Price = m_nPrice;  
         objNewProduct.StandardCost = m_nStandardCost;  
         objNewProduct.ListPrice = m_nListPrice;  
         objNewProduct.ProductTypeCode = nProductTypeCode;
         objNewProduct.ProductUrl = m_strProductUrl;
         objNewProduct.UnitOfMeasureId = m_guidUnitOfMeasureId;

         return objNewProduct;
      }

      static public string FormatCurrency(decimal nPrice, int nCurrencyFormatCode, string strCurrencySymbol)
      {
         string strResult = "";

         switch (nCurrencyFormatCode)
         {
            case 0:
               // $1
               strResult = strCurrencySymbol + nPrice.ToString(".00");
               break;

            case 1:
               // $ 1
               strResult = strCurrencySymbol + " " + nPrice.ToString(".00");
               break;
            
            case 2:
               // 1$
               strResult = nPrice.ToString(".00") + strCurrencySymbol;
               break;
            
            case 3:
               // 1 $                       
               strResult = nPrice.ToString(".00") + " " + strCurrencySymbol;
               break;


         }

         return strResult;

      }
      
      public void LoadFromCrmProduct(product objCrmProduct, string strCustomField1, string strCustomField2)
      {
         this.AllowDiscounting = true; // By default, allow discounting
         this.DefaultUnitOfMeasureId = objCrmProduct.defaultuomid.Value;
         this.Description = objCrmProduct.description;
         this.IsKit = objCrmProduct.iskit.Value;           
         this.Name = objCrmProduct.name;

         if (objCrmProduct.price == null)
         {
            this.ListPrice = 0;
         }
         else
         {
            this.ListPrice = objCrmProduct.price.Value;
         }

         this.ProductId = objCrmProduct.productid.Value;
         this.ProductNumber = objCrmProduct.productnumber;

         this.ProductTypeCode = -1;
         if (objCrmProduct.producttypecode != null)
         {
            if (!objCrmProduct.producttypecode.IsNull)
            {
               this.ProductTypeCode = objCrmProduct.producttypecode.Value;
            }
         }

         this.ProductUrl = objCrmProduct.producturl;

         if (objCrmProduct.standardcost == null)
         {
            this.StandardCost = 0;
         } 
         else
         {
            this.StandardCost = objCrmProduct.standardcost.Value;
         }          

         if (strCustomField1 != "")
         {
            Type objType = objCrmProduct.GetType();
            FieldInfo objVariable = objType.GetField(strCustomField1);

            if (objVariable != null)
            {
               object objValue = objVariable.GetValue(objCrmProduct);
            
               if (objValue != null)
                  this.CustomField1 = objValue.ToString();
            }
         }

         if (strCustomField2 != "")
         {
            Type objType = objCrmProduct.GetType();
            FieldInfo objVariable = objType.GetField(strCustomField2);

            if (objVariable != null)
            {
               object objValue = objVariable.GetValue(objCrmProduct);
            
               if (objValue != null)
                  this.CustomField2 = objValue.ToString();
            }
         }   
      }
          
      /*
        * <product>
             <description>
               Suitable for any type of riding, on or off-road. Fits any budget. Smooth-shifting with a comfortable ride.
             </description>
             <iskit>0</iskit>
             <name>Mountain-500 Black, 44</name>
             <price>539.99</price>
             <productid>{1EEB6F14-3386-42E3-93FE-298ED58442AC}</productid>
             <productnumber>BK-M18B-44</productnumber>
          </product>
        */
      public void LoadFromXml(string xmlData, string strCustomField1, string strCustomField2)
      {
         XmlDocument    doc = new XmlDocument();

         doc.LoadXml(xmlData);
         XmlNode     nodeRoot = doc.DocumentElement;
         LoadFromXmlNode(nodeRoot, strCustomField1, strCustomField2);
      }

      /*
      <resultset morerecords='0' paging-cookie='$1$$product$productid$1$0$38${371FCF3E-647B-44D1-B40B-A9C8CC738D90}$!$product$productid$1$0$38${371FCF3E-647B-44D1-B40B-A9C8CC738D90}$'>
         <result>
            <productid>{371FCF3E-647B-44D1-B40B-A9C8CC738D90}</productid>
            <defaultuomscheduleid name=\"Bike and Frame\" dsc=\"0\">{45F2A0AA-D503-42BD-BA51-68B384080831}</defaultuomscheduleid><subjectid name=\"Mountain Bikes\" dsc=\"0\">{6B5121E7-BF03-42B5-98A6-3E54E8864CC9}</subjectid>
            <organizationid name=\"Adventure Works Cycle\" dsc=\"0\">{5E83BB39-8020-4850-B328-D7144C99AFD1}</organizationid><name>Mountain-100 Black, 38</name><defaultuomid name=\"Single\" dsc=\"0\">{D805F977-2FC6-4206-BDE1-7D5B060525E8}</defaultuomid><pricelevelid name=\"Wholesale\" dsc=\"0\">{D8231AE0-9BEE-40FF-AE7A-FC722722B5F0}</pricelevelid><description>Top-of-the-line competition mountain bike. Performance-enhancing options include the innovative HL Frame, super-smooth front suspension, and traction for all terrain.</description><producttypecode name=\"Sales Inventory\" formattedvalue=\"1\">1</producttypecode>
            <price formattedvalue=\"$3,374.99\">3374.99</price>
            <iskit name=\"No\">0</iskit><productnumber>BK-M82B-38</productnumber><size>38</size><currentcost formattedvalue=\"$2,522.47\">2522.4675</currentcost><standardcost formattedvalue=\"$2,497.49\">2497.4926</standardcost><stockweight formattedvalue=\"20.35\">20.35</stockweight><quantitydecimal formattedvalue=\"0\">0</quantitydecimal><quantityonhand formattedvalue=\"155.00\">155</quantityonhand><isstockitem name=\"Yes\">1</isstockitem><createdon time=\"11:02 PM\" date=\"05/22/2004\">2004-05-22T23:02:10-04:00</createdon><modifiedon time=\"11:03 PM\" date=\"05/22/2004\">2004-05-22T23:03:47-04:00</modifiedon><createdby name=\"Administrator, System\" dsc=\"0\">{3B5020A6-7783-4909-9838-B286E3C76512}</createdby><statecode name=\"Active\" formattedvalue=\"0\">0</statecode><modifiedby name=\"Administrator, System\" dsc=\"0\">{3B5020A6-7783-4909-9838-B286E3C76512}</modifiedby>
            <statuscode name=\"Active\" formattedvalue=\"1\">1</statuscode>
         </result>
      </resultset>
      */
      public void LoadFromResultSetXml(string xmlData, string strCustomField1, string strCustomField2)
      {
         XmlDocument    doc = new XmlDocument();

         doc.LoadXml(xmlData);
         XmlNode     nodeRoot = doc.DocumentElement;
         XmlNode     nodeResultSet = nodeRoot.ChildNodes[0];
         LoadFromXmlNode(nodeResultSet, strCustomField1, strCustomField2);
      }

      public void LoadFromXmlNode(XmlNode nodeRoot, string strCustomField1, string strCustomField2)
      {
            
         foreach (XmlNode nodeItem in nodeRoot.ChildNodes)
         {  
            // check for custom fields
            if (nodeItem.Name == strCustomField1)
            {
               this.CustomField1 = nodeItem.InnerText;
            }
            else if (nodeItem.Name == strCustomField2)
            {
               this.CustomField2 = nodeItem.InnerText;
            }
            else
            {
               switch (nodeItem.Name)
               {
                  case "defaultuomid":               
                     this.DefaultUnitOfMeasureId = new Guid(nodeItem.InnerText);
                     break;

                  case "description":               
                     this.Description = nodeItem.InnerText;
                     break;

                  case "iskit":               
                     int   nValue = Convert.ToInt32(nodeItem.InnerText);
                     this.IsKit = Convert.ToBoolean(nValue);
                     break;

                  case "name":               
                     this.Name = nodeItem.InnerText;
                     break;              

                  case "price":               
                     this.ListPrice = Convert.ToDecimal(nodeItem.InnerText);
                     break;

                  case "productid":               
                     this.ProductId = new Guid(nodeItem.InnerText);
                     break;

                  case "productnumber":               
                     this.ProductNumber = nodeItem.InnerText;
                     break;
               
                  case "producturl":               
                     this.ProductUrl = nodeItem.InnerText;
                     break;

                  case "standardcost":               
                     this.StandardCost = Convert.ToDecimal(nodeItem.InnerText);
                     break;
               }   
            }
  
         } // end foreach      
      }


      /*
       * <product>
             <description>
               Suitable for any type of riding, on or off-road. Fits any budget. Smooth-shifting with a comfortable ride.
             </description>
             <iskit>0</iskit>
             <name>Mountain-500 Black, 44</name>
             <price>539.99</price>
             <productid>{1EEB6F14-3386-42E3-93FE-298ED58442AC}</productid>
             <productnumber>BK-M18B-44</productnumber>
          </product>
          */
      public string ToXmlString()
      {
         StringBuilder sb = new StringBuilder(700);
   
       //  sb.Append("<?xml version=\"1.0\" encoding=\"utf-16\"?>");
        
         sb.Append("<product>\r\n");    
         sb.Append("   <description>" + m_strDescription + "</description>\r\n");
         sb.Append("   <iskit>0</iskit>\r\n");
         sb.Append("   <name>" + m_strName + "</name>\r\n");
         sb.Append("   <price>" + m_nPrice.ToString() + "</price>\r\n");

         if (m_guidProductId != Guid.Empty)
         {
            sb.Append("   <productid>{" + m_guidProductId.ToString() + "}</productid>\r\n");
         }
         
         sb.Append("   <productnumber>" + m_strProductNumber + "</productnumber>\r\n");
         
         // HARD-CODED ENTRIES
         sb.Append("   <organizationid>{" + m_guidOrganizationId + "}</organizationid>\r\n");
         sb.Append("   <statecode>" + "0" + "</statecode>\r\n");
         sb.Append("   <statuscode>" + "1" + "</statuscode>\r\n");
         sb.Append("   <defaultuomscheduleid>{" + m_guidDefaultUomScheduleId + "}</defaultuomscheduleid>\r\n"); 
         sb.Append("   <defaultuomid>{" + m_guidDefaultUnitOfMeasureId + "}</defaultuomid>\r\n"); 
         sb.Append("</product>\r\n");
      
         return sb.ToString();
      }

      public product CreateCrmObject()
      {
         product objCrmProduct = new product();

         objCrmProduct.description = this.Description;

         objCrmProduct.iskit = new CrmBoolean();
         objCrmProduct.iskit.Value = this.IsKit;

         objCrmProduct.name = this.Name;

         objCrmProduct.price = new CrmMoney();
         objCrmProduct.price.Value = this.Price;

         objCrmProduct.productid = new Key();
         objCrmProduct.productid.Value = this.ProductId;

         objCrmProduct.productnumber = this.ProductNumber;

         objCrmProduct.organizationid = new Lookup();
         objCrmProduct.organizationid.Value = m_guidOrganizationId;
 
         objCrmProduct.statecode = new ProductStateInfo();
         objCrmProduct.statecode.Value = ProductState.Active;

         objCrmProduct.statuscode = new Status();
         objCrmProduct.statuscode.Value = 1;
         
         objCrmProduct.defaultuomscheduleid = new Lookup();
         objCrmProduct.defaultuomscheduleid.Value = m_guidDefaultUomScheduleId;
         
         objCrmProduct.defaultuomid = new Lookup();
         objCrmProduct.defaultuomid.Value = m_guidDefaultUnitOfMeasureId;

         return objCrmProduct;
      }


   } // end class
}
